package site.sorghum.ddl.extra;

import java.util.HashMap;
import java.util.Map;

/**
 * 一个忽略键大小写的 HashMap 实现
 *
 * @param <V> 值的类型
 */
public class IgnoreHashMap<V> extends HashMap<String, V> {

    /**
     * 键的忽略规则枚举
     */
    public enum IgnoreRule {
        CASE_INSENSITIVE, // 忽略大小写
        TRIM,            // 忽略前后空格
        CASE_INSENSITIVE_AND_TRIM // 忽略大小写和前后空格
    }

    private final IgnoreRule ignoreRule;

    /**
     * 使用默认的忽略大小写规则构造 IgnoreHashMap
     */
    public IgnoreHashMap() {
        this(IgnoreRule.CASE_INSENSITIVE);
    }

    /**
     * 使用指定的忽略规则构造 IgnoreHashMap
     *
     * @param ignoreRule 键的忽略规则
     */
    public IgnoreHashMap(IgnoreRule ignoreRule) {
        super();
        this.ignoreRule = ignoreRule;
    }

    /**
     * 使用指定的初始容量和忽略规则构造 IgnoreHashMap
     *
     * @param initialCapacity 初始容量
     * @param ignoreRule      键的忽略规则
     */
    public IgnoreHashMap(int initialCapacity, IgnoreRule ignoreRule) {
        super(initialCapacity);
        this.ignoreRule = ignoreRule;
    }

    /**
     * 使用指定的 Map 和忽略规则构造 IgnoreHashMap
     *
     * @param m          要复制的 Map
     * @param ignoreRule 键的忽略规则
     */
    public IgnoreHashMap(Map<? extends String, ? extends V> m, IgnoreRule ignoreRule) {
        super();
        this.ignoreRule = ignoreRule;
        putAll(m);
    }

    /**
     * 处理键的方法，根据忽略规则转换键
     *
     * @param key 原始键
     * @return 处理后的键
     */
    private String processKey(Object key) {
        if (key == null) {
            return null;
        }

        String strKey = key.toString();
        switch (ignoreRule) {
            case CASE_INSENSITIVE:
                return strKey.toLowerCase();
            case TRIM:
                return strKey.trim();
            case CASE_INSENSITIVE_AND_TRIM:
                return strKey.trim().toLowerCase();
            default:
                return strKey;
        }
    }

    @Override
    public V get(Object key) {
        return super.get(processKey(key));
    }

    @Override
    public V put(String key, V value) {
        return super.put(processKey(key), value);
    }

    @Override
    public void putAll(Map<? extends String, ? extends V> m) {
        for (Map.Entry<? extends String, ? extends V> entry : m.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public boolean containsKey(Object key) {
        return super.containsKey(processKey(key));
    }

    @Override
    public V remove(Object key) {
        return super.remove(processKey(key));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof IgnoreHashMap)) return false;
        if (!super.equals(o)) return false;

        IgnoreHashMap<?> that = (IgnoreHashMap<?>) o;
        return ignoreRule == that.ignoreRule;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + (ignoreRule != null ? ignoreRule.hashCode() : 0);
        return result;
    }
}